/*
srkrt_ia.c
Ce fichier regroupe le corps de l'ensemble des fonction utilisées par l'intelligence artificielle.
*/

#include "srkrt_ia.h"
#include <stdlib.h>
#include <stdio.h>

int srkrt_ia_heuristic(Surakarta game) {
	
	int r ; /* Valeur renvoyé par la fonction */
	
	switch(srkrt_ia_result(game)) {
		case DRAW : /* En cas d'égalité, la valeur de la position est nulle. */
			return 0 ;
		case PLAYER_1_WON : 
			return MIN_H_VALUE ; /* Si un joueur a gagné, la valeur de la position est minimal ou maximal, respectivement */
		case PLAYER_2_WON :
			return MAX_H_VALUE ;
		default :
			/* Si la partie n'est pas finie, l'heuristique va atribuer une note entre les deux extrèmes. */
			/* Pour cela, elle se base sur le nombres de pions restants. */
			r = game.player2Left-game.player1Left ;
			if(r==0)
				r=game.toPlay ;
			else
				r*=2 ;
			return r ;
	}	
}


int srkrt_ia_result(Surakarta game) {
	
	List allowedMoves ; /* Contiendra la liste des coups autorisés. */
	int rtrn ; /* Valeur renvoyée par la fonction */
	Iter iter ; /* Itérateur sur la liste allowedMoves */ 
	Move m ;
	
	/* Cas où un des deux joueurs a gagné */
	if(game.player1Left==0) {
		return PLAYER_2_WON ;
	} else if(game.player2Left==0) {
		return PLAYER_1_WON ;
	
	/* On commence par vérifier si la partie n'est pas nulle (1 vs 1). */
	} else if((game.player1Left==1) && (game.player2Left==1)) { /* Il reste un pion a chaque joueur */
		if((game.board[0][0]==VOID) && (game.board[0][5]==VOID)) {
			if((game.board[5][0]==VOID) && (game.board[5][5])==VOID) {
				allowedMoves=srkrt_list_create() ;
				srkrt_allowed_moves(&game,&allowedMoves) ;
				iter = srkrt_iter_create(&allowedMoves);
				rtrn=DRAW ; 
				/* Si on trouve un coup où un joueur prend l'autre, la partie n'est pas finie. */
				/* Sinon, il y a égalité */
				while ( (iter != NULL) && (rtrn != NOT_OVER) ) {
					m = srkrt_iter_get_value(iter) ;
					if ( m.capture ) {
						rtrn = NOT_OVER;
					}
					srkrt_iter_next(&iter);
				}
				return rtrn ;
			}
		}
		return NOT_OVER ;
	} else {
		return NOT_OVER ;
	}
}


int max(int a, int b) {
	if(a>=b)
		return a ;
	else
		return b ;
}

int min(int a, int b) {
	if(a<=b)
		return a ;
	else
		return b ;
}


int srkrt_ia_alphabeta(Surakarta game, int alpha, int beta, int iterLeft) {
	
	List allowedMoves ;
	int best ;
	/*int i ;*/
	Iter iter;
	
	/* Si on est sur une feuille (!NOT_OVER) ou si on a atteind l'horizon (iterLeft==0), on evalue le noeud */
	if((srkrt_ia_result(game)!=NOT_OVER) || (iterLeft==0)) {
		return srkrt_ia_heuristic(game) ;
	} else { /* Sinon, on va lancer l'algo alpha-beta */
		/* Calculs des coup possibles a partir de ce noeud. */
		allowedMoves=srkrt_list_create() ;
		srkrt_allowed_moves(&game, &allowedMoves) ;
		iter = srkrt_iter_create(&allowedMoves);

		/* Cas du noeud MIN */
		if(game.toPlay==PLAYER_1) {
			best=MAX_H_VALUE ;
			while ( iter != NULL ) {
				srkrt_play(&game, srkrt_iter_get_value(iter));
				best=min(best, srkrt_ia_alphabeta(game,alpha,beta,iterLeft-1)) ;
				srkrt_take_back(&game) ;
				if(alpha>=best) { /* Coupure alpha */
					srkrt_list_destroy(&allowedMoves);
					return best ;
				}
				beta=min(beta,best) ;
				srkrt_iter_next(&iter);
			}
		} else { /* Cas du noeud MAX */
			best=MIN_H_VALUE ;
			while ( iter != NULL ) {
				srkrt_play(&game, srkrt_iter_get_value(iter));
				best=max(best, srkrt_ia_alphabeta(game,alpha,beta,iterLeft-1)) ;
				srkrt_take_back(&game) ;
				if(alpha<=best) { /* Coupure alpha */
					srkrt_list_destroy(&allowedMoves);
					return best ;
				}
				alpha=max(alpha,best) ;
				srkrt_iter_next(&iter);
			}
		}
		srkrt_list_destroy(&allowedMoves);
		return best ;
	}
}


Move srkrt_ia_bestMove(Surakarta game) {
	
	List allowedMoves ;
	int bestVal ;
	int alphabetaResult ;
	int maxDepth = game.level;
	Move m ;
	Iter iter;

	if(srkrt_ia_result(game)!=NOT_OVER) {
		return m ; 
	} else { /* Si la partie n'est pas terminée */
		allowedMoves=srkrt_list_create() ;
		srkrt_allowed_moves(&game, &allowedMoves) ;
		iter = srkrt_iter_create(&allowedMoves);

		/* Cas MIN */
		if(game.toPlay==PLAYER_1) {
			bestVal=MAX_H_VALUE ;

			while ( iter != NULL ) { /* On va chercher quel coup mène à la plus petite valeur par alphaBeta */
				srkrt_play(&game, srkrt_iter_get_value(iter));
				alphabetaResult=srkrt_ia_alphabeta(game,MIN_H_VALUE,MAX_H_VALUE,maxDepth) ;
				srkrt_take_back(&game) ;
				if(alphabetaResult==bestVal) {
					if(rand()%2) /* On insère une part de hasard pour varier les coups */
						m=srkrt_iter_get_value(iter) ;
				} else if(alphabetaResult<bestVal) {
					bestVal=alphabetaResult ;
					m=srkrt_iter_get_value(iter) ;
				}
				srkrt_iter_next(&iter);
			}
		} else { /* Cas MAX */
			bestVal=MIN_H_VALUE ;

			while ( iter != NULL ) { /* On va chercher quel coup mène à la plus grande valeur par alphaBeta */
				srkrt_play(&game, srkrt_iter_get_value(iter));
				alphabetaResult=srkrt_ia_alphabeta(game,MIN_H_VALUE,MAX_H_VALUE,maxDepth) ;
				srkrt_take_back(&game) ;
				if(alphabetaResult==bestVal) {
					if(rand()%2) /* On insère une part de hasard pour varier les coups */
						m=srkrt_iter_get_value(iter) ;
				} else if(alphabetaResult>bestVal) {
					bestVal=alphabetaResult ;
					m=srkrt_iter_get_value(iter) ;
				}
				srkrt_iter_next(&iter);
			}

		}
		
		srkrt_list_destroy(&allowedMoves);

		return m ;
	}
}

